﻿using System;
using System.ServiceModel;

using WSU.Cheka.Duplex.Contracts;

namespace WSU.Cheka.Duplex.Client
{
    sealed class DisplayCallback : IResultCallback
    {
        public void Display(float x, float y, string opSymbol, float result)
        {
            Console.WriteLine("{0} {1} {2} = {3}", x, opSymbol, y, result);
        }
    }

    sealed class DuplexCalculateClient : DuplexClientBase<ICalculation>, ICalculation
    {
        #region "constructor"

        public DuplexCalculateClient(InstanceContext context, string endpntCfgName)
            : base(context, endpntCfgName)
        { }

        #endregion

        #region "implement contract interface"
        public void Add(float x, float y)
        {
            base.Channel.Add(x, y);
        }

        public void Substract(float x, float y)
        {
            base.Channel.Substract(x, y);
        }

        public void Multiple(float x, float y)
        {
            base.Channel.Multiple(x, y);
        }

        public void Divide(float x, float y)
        {
            base.Channel.Divide(x, y);
        }
        #endregion
    }

    static class Program
    {
        private static void Invoke(this ICalculation proxy)
        {
            proxy.Add(1, 2);
            proxy.Substract(3, 4);
            proxy.Multiple(5, 6);
            proxy.Divide(8, 7);
        }

        private static void CallViaChannelFactory()
        {
            InstanceContext context = new InstanceContext(new DisplayCallback());
            using (DuplexChannelFactory<ICalculation> chFactory = new DuplexChannelFactory<ICalculation>(context, "CalculateClient"))
            {
                ICalculation proxy = chFactory.CreateChannel();
                using (proxy as IDisposable)
                {
                    proxy.Invoke();

                    // chekanote: must call "readline" within the using block, to avoid the proxy to be disposed
                    // otherwise the proxy will be disposed, which cause the TCP channel to be closed
                    // since the request and the callback use the same TCP socket as the communication channel
                    // then since proxy disposed-->channel closed, then the receiver side will never get the callback
                    // (maybe at the server side, exception may be thrown out when invoking that callback)
                    Console.WriteLine("Press any key to exit the client,......");
                    Console.ReadLine();
                }
            }
        }

        private static void CallViaUserdefProxy()
        {
            // chekanote: pay attention that there is only one callback instance
            // (associate each proxy with an individual callback instance, may can provide some isolation among these
            // callback instances, to avoid race)
            InstanceContext context = new InstanceContext(new DisplayCallback());
            using (DuplexCalculateClient proxy = new DuplexCalculateClient(context, "CalculateClient"))
            {
                proxy.Invoke();
                Console.WriteLine("Press any key to exit the client,......");
                Console.ReadLine();
            }
        }

        static void Main(string[] args)
        {
            CallViaChannelFactory();
            CallViaUserdefProxy();
        }
    }
}
